/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

package bgtp;

import java.util.*;
import java.nio.*;
import java.net.*;
import java.nio.channels.*;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.lang.InterruptedException;
import java.io.IOException;

/**
 *реализация транспорта для TCP протокола
 */
public class TCPTransport
{
    private int         socketTimeout = 5000;
    private String	host	      = "";
    private int         port          = -1;
    private BGTPLog	logger;
    
    public TCPTransport(String hostStr, String portStr)
    {
	host   = hostStr;
	port   = Integer.parseInt(portStr);
	logger = new BGTPLog("TCPTransport");
    }

    public TCPClient getClient() throws IOException
    {
	//отыграть коннект и вернуть соединение
	SocketChannel conn = SocketChannel.open();
	conn.connect(new InetSocketAddress(host, port));    
	return new TCPClient(conn);
    }

    public TCPServer getServer() throws IOException
    {
	//вкрнуть инстанс сервева
	return new TCPServer(port);
    }

    /**
     *реализация интерфейса Transport для TCP 
     */
    public class TCPClient implements Transport
    {
	private SocketChannel	sc	    = null;
	private ByteBuffer      buffer	    = null;
	private long		bytecounter = 0;
	private byte[] tmparray;
	
	/**конструяктор
	 *@param channel уже сконекченный сокет
	 */
	public TCPClient(SocketChannel channel)
	{
	    sc = channel;
	}

	/**
	 *изменение режима работы канала. блокирующий неблокирующий
	 *@param newVal новое знчение состояния true - блокирующий, false - нет
	 *@return признак успешности операции
	 */
	public boolean setBlocking(boolean newVal)
	{
	    try
		{
		    sc.configureBlocking(newVal);
		}
	    catch(IOException ioe)
		{
		    ioe.printStackTrace();
		    logger.error("TCPClient()", "Set socket to (non)blocking fail");
		    return false;
		}
	    return true;
	}

	/**
	 *закрыть соединение
	 */
	public void close()
	{
	    try
		{
		    sc.close();
		}
	    catch(IOException ioe)
		{
		    ioe.printStackTrace();
		}
	    sc = null;
	}

	/**
	 *количество прочитанных записанных байт
	 *@return количество прочитанных записанных байт
	 */
	public long count()
	{
	    return bytecounter;
	}

	/**
	 *прочитать блок данных
	 *@param maxLen ограничние размера блока сверху
	 *@return данные преобразованные в строку
	 */
	public String readBlock(int maxLen) 
	{
	    buffer	    = ByteBuffer.allocate(maxLen);
	    String	rst = "";

	    try
		{
		    //System.out.println(">");
		    bytecounter = sc.read(buffer);
		    if(bytecounter > 0)
			{
			    buffer.rewind();
			    tmparray = new byte[(int)bytecounter];
			    buffer.get(tmparray);
			    rst	     = new String(tmparray);
			    //System.out.printf("readBlock-%s-ln%d ln*%d\n---\n", rst, rst.length(),bytecounter);
			    return rst;
			}
		}
	    catch(IOException ioe)
		{
		    ioe.printStackTrace();
		}
	    return rst;
	}

	/**
	 *записать блок данных в канал
	 *@param str строка подлежащая записи
	 *@return количество реальнозаписанных байт
	 */
	public long writeBlock(String str)
	{
	    byte[] barray = str.getBytes();
	    buffer	  = ByteBuffer.allocate(barray.length);
	    buffer.put(barray);
	    buffer.rewind();

	    //System.out.println("writeBlock-"+str);
	    try
		{
		    while(buffer.hasRemaining())
			{
			    sc.write(buffer);
			}
		    bytecounter = buffer.position();
		    return bytecounter;
		}
	    catch(IOException ioe)
		{
		    ioe.printStackTrace();
		}
	    return -1;
	}

    }

    public class TCPServer
    {
	private ServerSocketChannel	ssc = null;

	public TCPServer(int port) throws IOException
	{
	    ssc = ServerSocketChannel.open();
	    ssc.socket().bind (new InetSocketAddress(port));
	}

	public TCPClient getConnection() throws IOException
	{
	    return new TCPClient(ssc.accept());
	}
    }
}

